/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/mydns/conf.c,v 1.20 2002/12/08 17:34:42 bboy Exp $
	conf.c: Routines to read the configuration file.

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "named.h"

#include <pwd.h>
#include <grp.h>

CONF	 *Conf = (CONF *)NULL;									/* Config options */
int	 opt_daemon = 0;											/* Run in background? (-d, --daemon) */
char	 *opt_conf = MYDNS_CONF;								/* Location of config file (-c, --conf) */
uid_t	 perms_uid = 0;											/* User permissions */
gid_t	 perms_gid = 0;											/* Group permissions */
time_t task_timeout;												/* Task timeout */
int	 axfr_enabled = 0;										/* Enable AXFR? */
int	 tcp_enabled = 0;											/* Enable TCP? */


/* Returns 1 for "[Yy](es)", "[Tt](rue)", "1", or "(o)[Nn]" */
#define  atobool(str)   \
   (str && (str[0] == 'Y' || str[0] == 'y' || str[0] == 'T' || str[0] == 't' || \
   str[0] == '1' || str[1] == 'n' || str[1] == 'N'))

/* Default config values */
static CONF defConfig[] = {
/* Name					Value							Description	*/
{	"-",					NULL,							N_("DATABASE INFORMATION")},
{	"db-host",			"localhost",				N_("SQL server hostname")},
{	"db-user",			"user",						N_("SQL server username")},
{	"db-password",		"password",					N_("SQL server password")},
{	"database",			PACKAGE_NAME,				N_("MyDNS database name")},

{	"-",					NULL,							N_("GENERAL OPTIONS")},

{	"user",				"nobody",					N_("Run with the permissions of this user")},
{	"group",				"nogroup",					N_("Run with the permisisons of this group")},
{	"listen",			"*",							N_("Listen on these addresses ('*' for all)"),	"bind"},

{	"-",					NULL,							N_("CACHE OPTIONS")},

{	"cache-size",		"16384",						N_("Maximum number of elements stored in the cache")},
{	"cache-expire",	"60",							N_("Number of seconds after which cached data expires")},

{	"-",					NULL,							N_("ESOTERICA")},
{	"log",				"LOG_DAEMON",				N_("Facility to use for program output (LOG_*/stderr)")},
{	"pidfile",			"/var/run/"PACKAGE_NAME".pid",	N_("Path to PID file")},
{	"timeout",			"5",							N_("Number of seconds after which queries time out")},
{	"multicpu",			"1",							N_("Number of CPUs installed on your system")},
{	"allow-axfr",		"no",							N_("Should AXFR be enabled?")},
{	"allow-tcp",		"no",							N_("Should TCP be enabled?")},
{	"soa-table",		MYDNS_SOA_TABLE,			N_("Name of table containing SOA records")},
{	"rr-table",			MYDNS_RR_TABLE,			N_("Name of table containing RR data")},
{	"ptr-table",		MYDNS_PTR_TABLE,			N_("Name of table containing PTR records")},

{	NULL,					NULL,							NULL}
};


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	DUMP_CONFIG
	Output configuration info (in a sort of config-file format).
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
dump_config(void)
{
	time_t time_now = time(NULL);
	int len = 0, w = 0, n;
	char pair[512];
	CONF *c;

	printf("\
##
##  "MYDNS_CONF"
##  %.24s
##  %s
##
", ctime(&time_now), _("For more information, see mydns.conf(5)."));

	/* Look up description for configured variables and determine longest name/value pair length */
	for (n = 0; defConfig[n].name; n++)
	{
		char *value = conf_get(&Conf, defConfig[n].name);

		c = &defConfig[n];
		if (!value)
		{
			if ((len = strlen(c->name) + (c->value ? strlen(c->value) : 0)) > w)
				w = len;
		}
		else
		{
			char *cp, *vbuf, *v;
			if (!strcasecmp(c->name, "listen"))
			{
				while ((cp = strchr(value, ',')))
					*cp = CONF_FS_CHAR;
			}
			vbuf = xstrdup(value);
			for (cp = vbuf; (v = strsep(&cp, CONF_FS_STR));)
				if ((len = strlen(c->name) + strlen(v)) > w)
					w = len;
			free(vbuf);
		}
	}
	w += strlen(" = ");

	for (n = 0; defConfig[n].name; n++)
	{
		char *value = conf_get(&Conf, defConfig[n].name);

		c = &defConfig[n];
		if (!value)
			value = c->value;
		if (c->name[0] == '-')
			printf("\n\n%-*.*s\t# %s\n\n", w, w, " ", _(c->desc));
		else
		{
			if (!strcasecmp(c->name, "listen"))
			{
				char *cp, *vbuf, *v;
				while ((cp = strchr(value, ',')))
					*cp = CONF_FS_CHAR;
				vbuf = xstrdup(value);
				for (cp = vbuf; (v = strsep(&cp, CONF_FS_STR));)
				{
					if (v == vbuf)
					{
						snprintf(pair, sizeof(pair), "%s = %s", c->name, v);
						printf("%-*.*s\t# %s\n", w, w, pair, _(c->desc));
					}
					else
						printf("%s = %s\n", c->name, v);
				}
				free(vbuf);
			}
			else
			{
				snprintf(pair, sizeof(pair), "%s = %s", c->name, value);
				printf("%-*.*s\t# %s\n", w, w, pair, _(c->desc));
			}
		}
	}
	printf("\n");
}
/*--- dump_config() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CONF_SET_LOGGING
	Sets the logging type and opens the syslog connection if necessary.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
conf_set_logging(void)
{
	char logtype[80];

	strncpy(logtype, conf_get(&Conf, "log"), sizeof(logtype)-1);
	strtolower(logtype);

	if (!err_stderr)
		closelog();
	err_stderr = 0;

	if (!strcmp(logtype, "stderr")) err_stderr = 1;
	else if (!strcmp(logtype, "log_daemon")) error_init(NULL, LOG_DAEMON);
	else if (!strcmp(logtype, "log_local0")) error_init(NULL, LOG_LOCAL0);
	else if (!strcmp(logtype, "log_local1")) error_init(NULL, LOG_LOCAL1);
	else if (!strcmp(logtype, "log_local2")) error_init(NULL, LOG_LOCAL2);
	else if (!strcmp(logtype, "log_local3")) error_init(NULL, LOG_LOCAL3);
	else if (!strcmp(logtype, "log_local4")) error_init(NULL, LOG_LOCAL4);
	else if (!strcmp(logtype, "log_local5")) error_init(NULL, LOG_LOCAL5);
	else if (!strcmp(logtype, "log_local6")) error_init(NULL, LOG_LOCAL6);
	else if (!strcmp(logtype, "log_local7")) error_init(NULL, LOG_LOCAL7);
	else Warnx("\"%s\": %s", conf_get(&Conf, "log"), _("unknown logging facility"));
}
/*--- conf_set_logging() ------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_CONFIG_FILE_PERMS
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
check_config_file_perms(void)
{
	FILE *fp;

	if ((fp = fopen(opt_conf, "r")))
	{
		Warnx("%s: %s", opt_conf, _("WARNING: config file is readable by unprivileged user"));
		fclose(fp);
	}
}
/*--- check_config_file_perms() -----------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	LOAD_CONFIG
	Load the configuration file.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
load_config(void)
{
	int n;
	struct passwd *pwd = NULL;
	struct group *grp = NULL;

	/* Load config */
	conf_load(&Conf, opt_conf);

	/* Set defaults */
	for (n = 0; defConfig[n].name; n++)
	{
		if (defConfig[n].name[0] == '-')
			continue;
		if (!conf_get(&Conf, defConfig[n].name))
			conf_set(&Conf, defConfig[n].name, defConfig[n].value);
	}

	/* Support "mysql-user" etc. for backwards compatibility */
	if (conf_get(&Conf, "mysql-host"))
		conf_set(&Conf, "db-host", conf_get(&Conf, "mysql-host"));
	if (conf_get(&Conf, "mysql-user"))
		conf_set(&Conf, "db-user", conf_get(&Conf, "mysql-user"));
	if (conf_get(&Conf, "mysql-pass"))
		conf_set(&Conf, "db-password", conf_get(&Conf, "mysql-pass"));
	if (conf_get(&Conf, "mysql-password"))
		conf_set(&Conf, "db-password", conf_get(&Conf, "mysql-password"));

#if HAVE_GETPWUID
	/* Set default for database username to real username if none was provided */
	if (!conf_get(&Conf, "db-user"))
	{
		struct passwd *pwd;
		if ((pwd = getpwuid(getuid())) && pwd->pw_name)
		{
			conf_set(&Conf, "db-user", pwd->pw_name);
			memset(pwd, 0, sizeof(struct passwd));
		}
	}
#endif

	/* Load user/group perms */
	if (!(pwd = getpwnam(conf_get(&Conf, "user"))))
		Err(_("error loading uid for user `%s'"), conf_get(&Conf, "user"));
	perms_uid = pwd->pw_uid;
	perms_gid = pwd->pw_gid;
	memset(pwd, 0, sizeof(struct passwd));

	if (!(grp = getgrnam(conf_get(&Conf, "group"))) && !(grp = getgrnam("nobody")))
	{
		Warnx(_("error loading gid for group `%s'"), conf_get(&Conf, "group"));
		Warnx(_("using gid %lu from user `%s'"), (unsigned long)perms_gid, conf_get(&Conf, "user"));
	}
	else
	{
		perms_gid = grp->gr_gid;
		memset(grp, 0, sizeof(struct group));
	}

	/* We call conf_set_logging() again after moving into background, but it's called here
		to report on errors. */
	conf_set_logging();

	/* Set global options */
	task_timeout = atou(conf_get(&Conf, "timeout"));
	axfr_enabled = atobool(conf_get(&Conf, "allow-axfr"));
	tcp_enabled = atobool(conf_get(&Conf, "allow-tcp"));

	/* Set table names if provided */
	mydns_set_soa_table_name(conf_get(&Conf, "soa-table"));
	mydns_set_rr_table_name(conf_get(&Conf, "rr-table"));
	mydns_set_ptr_table_name(conf_get(&Conf, "ptr-table"));
}
/*--- load_config() -----------------------------------------------------------------------------*/

/* vi:set ts=3: */
/* NEED_PO */
